package gui;

import gameObjects.Castle;
import gameObjects.GameObject;
import gameObjects.Terrain;
import gameObjects.Unit;

import java.awt.Color;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

import castlewarserver.Connector;

public class MouseEvents  implements MouseListener,ActionListener{

	MainWindow mainWindow;
	Connector connector;
	CastleMenu castleMenu;
	ArrayList <JLabel> rangeLabels = new ArrayList<JLabel>();

	public MouseEvents(MainWindow mainWindow, Connector connector){
		this.mainWindow=mainWindow;
		this.connector=connector;
	}



	@Override
	public void mouseClicked(MouseEvent event) {
		if (mainWindow.actualPlayer.equalsIgnoreCase(mainWindow.player)){
			undrawRange();
			//usunięcie obramowania
			if(mainWindow.clickedObject != null){
				mainWindow.clickedObject.setBorder(null);
			}

			GuiObject guiObj =(GuiObject) event.getSource();

			if (guiObj.getGameObject().getObjectType().equalsIgnoreCase("TERRAIN") ){
				terrainClicked(guiObj);
			}

			if (guiObj.getGameObject().getObjectType().equalsIgnoreCase("UNIT") ){
				unitClicked(guiObj);
			}

			if (guiObj.getGameObject().getObjectType().equalsIgnoreCase("CASTLE") ){
				castleClicked(guiObj);
			}

			//dodanie obramowania
			if(mainWindow.clickedObject != null){	
				mainWindow.clickedObject.setBorder( BorderFactory.createLineBorder(Color.red) );
			}
		}
		else{
			// nic nie rob
		}
	}

	private void terrainClicked(GuiObject guiObj){
		// drugi klik
		if ( mainWindow.clickedObject != null 
				&& !mainWindow.clickedObject.getGameObject().getObjectType().equalsIgnoreCase("CASTLE") ){
			Terrain terrain = (Terrain) guiObj.getGameObject();
			if ( terrain.isWalkable() ){
				Unit unit= (Unit) mainWindow.clickedObject.getGameObject();
				if(rangeCheck(unit, terrain)){
					mainWindow.clickedObject.setGameObject(connector.moveUnit(unit,terrain.getX(),terrain.getY()));
					mainWindow.reDrawGuiObject(mainWindow.clickedObject);
					mainWindow.clickedObject = null;
				}
			}
		}
		//pierwszy klik
		else{
			mainWindow.clickedObject= null;
		}
	}

	private boolean rangeCheck(Unit unit, GameObject obj){
		boolean result = true;
		if ( (Math.abs(obj.getX() - unit.getX()) > unit.getRange())
				|| (Math.abs(obj.getY() - unit.getY()) > unit.getRange()) ){
			result = false;
		}


		return result;
	}

	private void unitClicked(GuiObject guiObj){

		Unit defender = (Unit)guiObj.getGameObject();

		if (defender.getPlayer().equalsIgnoreCase(mainWindow.player)){
			if ( !defender.isChanged() ){
				mainWindow.clickedObject=guiObj;
				drawRange(guiObj);
			}
			else{
				// nic nie rob
			}
		}
		else{
			if (mainWindow.clickedObject != null){
				if (mainWindow.clickedObject.getGameObject().getObjectType().equalsIgnoreCase("UNIT")) {
					Unit attacker = (Unit)mainWindow.clickedObject.getGameObject();

					if( defender.getPlayer().equalsIgnoreCase(attacker.getPlayer()) ){
						mainWindow.clickedObject=guiObj;
					}
					else{
						if(rangeCheck(attacker, defender)){

							System.out.println("ATTACK");
							Unit[] pair=connector.attackUnit(attacker, defender);
							attacker=pair[0];
							defender = pair[1]; 

							mainWindow.clickedObject.setGameObject(attacker);
							guiObj.setGameObject(defender);

							AttackThread thread = new AttackThread(guiObj,attacker.getDamage(),mainWindow.layeredPane);
							ExecutorService serviceExec = Executors.newCachedThreadPool();
							serviceExec.submit(thread);
							serviceExec.shutdown();

							System.out.println("attacker damage "+attacker.getDamage());
							System.out.println("defender hp "+ defender.getHp());
							if (defender.getHp() <= 0){
								if (attacker.getPlayer().equalsIgnoreCase("ORANGE")){
									Castle castle = connector.getCastle("ORANGE");
									mainWindow.castleOrange.setGameObject(castle);
									castleMenu.castle=castle; 
								}
								else{
									Castle castle = connector.getCastle("BLUE");
									mainWindow.castleBlue.setGameObject(castle);
									castleMenu.castle=castle; 
								}
								mainWindow.layeredPane.remove(guiObj);
								mainWindow.units.remove(guiObj);
								castleMenu.update();
								JOptionPane.showMessageDialog(mainWindow.mainFrame, "You get "+defender.getGold()+" gold.");

							}
							mainWindow.reDrawGuiObject(mainWindow.clickedObject);
							mainWindow.layeredPane.repaint();
							mainWindow.clickedObject = null;
						}
					}
				}
				// jeżeli kliknięty był zamek
				else  {
					// nic nie rob
				}
			}
		}


	}

	private void castleClicked(GuiObject guiObj){
		Castle castle =(Castle) guiObj.getGameObject();
		//gdy zamek gracza
		if ( castle.getPlayer().equalsIgnoreCase( mainWindow.player) ){
			mainWindow.clickedObject=guiObj;
			Point point=mainWindow.mainFrame.getLocation();
			castleMenu.setBounds(point.x+mainWindow.mainFrame.getWidth(),point.y,10,10);
			castleMenu.update();
			castleMenu.setVisible(true);

		}
		else{
			if(mainWindow.clickedObject != null){
				if (mainWindow.clickedObject.getGameObject().getObjectType().equalsIgnoreCase("UNIT") ){

					Unit unit = (Unit)mainWindow.clickedObject.getGameObject();
					// atakuj zamek
					if(rangeCheck(unit, castle)){
						unit=connector.attackCastle(unit);


						if (unit.getPlayer().equalsIgnoreCase("ORANGE")){
							castle = connector.getCastle("BLUE");
						}
						else{
							castle = connector.getCastle("ORANGE");
						}

						mainWindow.clickedObject.setGameObject(unit);
						guiObj.setGameObject(castle);

						AttackThread thread = new AttackThread(guiObj,unit.getDamage(),mainWindow.layeredPane);
						ExecutorService serviceExec = Executors.newCachedThreadPool();
						serviceExec.submit(thread);
						serviceExec.shutdown();

						System.out.println("unit damage "+unit.getDamage());
						System.out.println("castle hp "+ castle.getHp());
						if (castle.getHp() <= 0){
							mainWindow.endOfGame();
						}
						mainWindow.reDrawGuiObject(mainWindow.clickedObject);
						mainWindow.layeredPane.repaint();
						mainWindow.clickedObject = null;
					}

				}
			}
		}

	}

	private void drawRange(GuiObject guiObj){
		Unit unit = (Unit) guiObj.getGameObject();
		int range=unit.getRange();
		int x=unit.getX();
		int y=unit.getY();

		for(int i= x-range; i <= x+range; i++){

			for( int k = y-range; k <= y+range ; k++ ){
				if( k<0 || i<0){
					break;
				}

				JLabel label = new JLabel(new ImageIcon ("images\\range.png"));
				label.setOpaque(false);
				label.setBounds(i*GuiObject.W_SIZE, k*GuiObject.H_SIZE, GuiObject.W_SIZE, GuiObject.H_SIZE);
				rangeLabels.add(label);
				mainWindow.layeredPane.add(label);
				mainWindow.layeredPane.setLayer(label,2);
			}
		}

		mainWindow.layeredPane.repaint();
	}

	private void undrawRange(){
		for(JLabel label:rangeLabels){
			mainWindow.layeredPane.remove(label);
		}

		mainWindow.layeredPane.repaint();
		rangeLabels.clear();
	}




	@Override
	public void mouseEntered(MouseEvent event) {
		GuiObject guiObj =(GuiObject) event.getSource();



		if (guiObj.getGameObject().getObjectType().equalsIgnoreCase("UNIT") ){
			setUnitTooltip(guiObj);
		}

		if (guiObj.getGameObject().getObjectType().equalsIgnoreCase("CASTLE") ){
			setCastleTooltip(guiObj);
		}

	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		

	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		

	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
	

	}

	private void setUnitTooltip(GuiObject guiObj){
		Unit unit = (Unit) guiObj.getGameObject();
		StringBuffer buff = new StringBuffer();
		buff.append("<html>");
		buff.append("Player ").append(unit.getPlayer()).append("<br>");
		buff.append("Type ").append(unit.getObjectType()).append("<br>");
		buff.append("HP ").append(unit.getHp()).append("<br>");
		buff.append("Damage ").append(unit.getDamage());
		buff.append("</html>");

		guiObj.setToolTipText(buff.toString());
	}
	private void setCastleTooltip(GuiObject guiObj){
		Castle castle = (Castle) guiObj.getGameObject();
		StringBuffer buff = new StringBuffer();
		buff.append("<html>");
		buff.append("Player ").append(castle.getPlayer()).append("<br>");
		buff.append("HP ").append(castle.getHp());
		buff.append("</html>");

		guiObj.setToolTipText(buff.toString());
	}


	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(mainWindow.endTurnButton)){

			endTurn();
		}

	}

	private void endTurn(){
		connector.endTurn(mainWindow.player);
		mainWindow.actualPlayer = connector.getActualPlayer();

		WaitingThread thread = new WaitingThread(connector, mainWindow);
		ExecutorService serviceExec = Executors.newCachedThreadPool();
		serviceExec.submit(thread);
		serviceExec.shutdown();

		mainWindow.endTurnButton.setEnabled(false);
	}

	public void initGame(){
		mainWindow.actualPlayer = connector.getActualPlayer();
		if (mainWindow.actualPlayer.equalsIgnoreCase(mainWindow.player)){
			mainWindow.endTurnButton.setEnabled(true);
		}
		else{
			WaitingThread thread = new WaitingThread(connector, mainWindow);
			ExecutorService serviceExec = Executors.newCachedThreadPool();
			serviceExec.submit(thread);
			serviceExec.shutdown();

			mainWindow.endTurnButton.setEnabled(false);
		}
	}
}
